package com.wanghengzhi.kata;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;

/**
 * @author wanghengzhi
 * @since 2021/12/6 20:44
 */
public class Args {

    private static final char RULE_PREFIX = '-';
    private static final String SPACE = " ";
    private final Pattern validRulePatten = Pattern.compile("-[a-zA-Z]");
    private final Map<Character, RuleTypeEnum> ruleAndType;
    private final Map<Character, String> ruleAndValue = new HashMap<>();

    private Args(String args, Map<Character, RuleTypeEnum> ruleAndType) {
        this.ruleAndType = ruleAndType;
        parseArgs(args);
    }

    private void parseArgs(String args) {
        if (isEmpty(args)) {
            return;
        }

        String[] items = args.split(SPACE);
        for (int index = 0; index < items.length; index++) {
            checkItem(items, index);
            putIntoMap(items, index);
        }
    }

    private void putIntoMap(String[] items, int index) {
        String currentItem = items[index];
        if (!isRule(currentItem)) {
            return;
        }
        char letter = items[index].charAt(1);
        if (isLastItem(items, index)) {
            ruleAndValue.put(letter, "");
            return;
        }

        String nextItem = items[index + 1];
        if (isRule(nextItem)) {
            ruleAndValue.put(letter, "");
        } else {
            ruleAndValue.put(letter, nextItem);
        }
    }

    private boolean isLastItem(String[] items, int index) {
        return index == items.length - 1;
    }

    private boolean isEmpty(String args) {
        return args == null || "".equals(args);
    }

    private void checkItem(String[] items, int index) {
        String currentItem = items[index];
        if (isRule(currentItem)) {
            checkRule(items, index);
        } else {
            checkValue(items, index);
        }
    }

    private void checkValue(String[] items, int index) {
        String currentItem = items[index];
        if (!frontItemIsRule(items, index)) {
            throw new IllegalArgumentException("非法值：" + currentItem);
        }
    }

    private void checkRule(String[] items, int index) {
        String currentItem = items[index];
        checkRuleFormat(currentItem);
        char ruleLetter = currentItem.charAt(1);
        checkRuleDefined(ruleLetter);
        if (ruleAndType.get(ruleLetter) == RuleTypeEnum.BOOL) {
            if (!nextIsRule(items, index)) {
                throw new IllegalArgumentException("非法值：" + items[index + 1]);
            }
        }
    }

    private boolean nextIsRule(String[] items, int index) {
        if (index == items.length-1) {
            return true;
        }
        return isRule(items[index + 1]);
    }

    private boolean frontItemIsRule(String[] items, int index) {
        if (index == 0) {
           return false;
        }
        return isRule(items[index -1]);
    }

    private void checkRuleDefined(char ruleLetter) {
        boolean defined = this.ruleAndType.containsKey(ruleLetter);
        if (!defined) {
            throw new IllegalArgumentException("未定义指令：" + ruleLetter);
        }
    }

    private boolean isRule(String item) {
        return item.charAt(0) == RULE_PREFIX;
    }

    private void checkRuleFormat(String current) {
        boolean matches = validRulePatten.matcher(current).matches();
        if (!matches) {
            throw new IllegalArgumentException("指令格式不合法：" + current);
        }
    }

    public boolean getBoolean(char letter) {
        return contains(letter);
    }

    public Optional<Integer> getInteger(char letter) {
        boolean hasRule = ruleAndValue.containsKey(letter);
        if (!hasRule) {
            return Optional.empty();
        }
        String numberValue = ruleAndValue.get(letter);
        return Optional.of(Integer.parseInt(numberValue));
    }

    public boolean contains(char letter) {
        return ruleAndValue.containsKey(letter);
    }

    public static class ArgsBuilder {
        private final String args;
        private final Map<Character, RuleTypeEnum> rules = new HashMap<>();
        private final Pattern validRulePatten = Pattern.compile("[a-zA-Z]");

        public ArgsBuilder(String args) {
            this.args = args;
        }

        public ArgsBuilder addRule(char letter, RuleTypeEnum type) {
            boolean matches = validRulePatten.matcher(letter+"").matches();
            if (!matches) {
                throw new IllegalArgumentException("无效规则格式：" + letter);
            }
            rules.put(letter, type);
            return this;
        }

        public Args build() {
            return new Args(args, rules);
        }
    }

}
